home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
comm
/
dnet20us.2
< prev
next >
Wrap
Internet Message Format
|
1989-04-29
|
56KB
Path: xanth!nic.MR.NET!indri!lll-winken!ames!oliveb!sun!rishathra!page
From: page%rishathra@Sun.COM (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i103: dnet - networking code (unix side) v2.0, Part02/02
Message-ID: <101943@sun.Eng.Sun.COM>
Date: 29 Apr 89 02:38:19 GMT
Sender: news@sun.Eng.Sun.COM
Lines: 2495
Approved: page@sun.com
Submitted-by: dillon@postgres.berkeley.edu (Matt Dillon)
Posting-number: Volume 89, Issue 103
Archive-name: comm/dnet20-us.2
# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
# dnet/net.c
# dnet/internal.c
# dnet/globals.c
# dnet/files.c
# dnet/dnet.h
# dnet/dnet.c
# dnet/Makefile
# dnet/MODS
# dnet.servers
# doc/history
# doc/dnet.doc
# doc/putfiles.doc
# doc/dsoc.doc
# doc/dnetlib.doc
# doc/draw.doc
# lib/dnetlib.h
# lib/dnetlib.c
# lib/Makefile
# server/sgcopy.c
# server/sshell.c
# server/sloadav.c
# server/scopy.c
# server/Makefile
# server/servers.h
# This is archive 2 of a 2-part kit.
# This archive created: Thu Apr 27 15:41:48 1989
if `test ! -d dnet`
then
mkdir dnet
echo "mkdir dnet"
fi
echo "extracting dnet/net.c"
sed 's/^X//' << \SHAR_EOF > dnet/net.c
X
X/*
X * NET.C
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X *
X * NetWork raw device interface. Replace with whatever interface you
X * want.
X */
X
X#include "dnet.h"
X#include <sys/stat.h>
X
XRcvInt()
X{
X int n = read(0, RcvBuf + RcvData, RCVBUF - RcvData);
X if (n >= 0)
X RcvData += n;
X if (n <= 0) /* disallow infinite fast-timeout select loops */
X RExpect = 0;
X if (DDebug && n < 0) {
X write(2, "RcvInt ERR\n", 11);
X }
X}
X
Xstatic struct sgttyb ttym;
Xstatic struct stat Stat;
X
XNetOpen()
X{
X int async = 1;
X
X fstat(0, &Stat);
X fchmod(0, 0600);
X /*
X signal(SIGIO, RcvInt);
X */
X ioctl (0, TIOCGETP, &ttym);
X ttym.sg_flags |= RAW;
X ttym.sg_flags &= ~CBREAK;
X ttym.sg_flags &= ~ECHO;
X ioctl (0, TIOCSETP, &ttym);
X /*
X ioctl (0, FIOASYNC, &async);
X */
X ioctl (0, FIONBIO, &async);
X}
X
XNetClose()
X{
X int async = 0;
X
X fchmod(0, Stat.st_mode);
X ioctl (0, FIONBIO, &async);
X /*
X ioctl (0, FIOASYNC, &async);
X */
X ioctl (0, TIOCGETP, &ttym);
X ttym.sg_flags &= ~RAW;
X ttym.sg_flags |= ECHO;
X ioctl (0, TIOCSETP, &ttym);
X}
X
XNetWrite(buf, bytes, expectreply)
Xubyte *buf;
X{
X if (expectreply)
X DidWrite = 1;
X if (DDebug)
X fprintf(stderr, "NETWRITE %08lx %ld\n", buf, bytes);
X gwrite(0, buf, bytes);
X}
X
Xgwrite(fd, buf, bytes)
Xregister char *buf;
Xregister long bytes;
X{
X register long n;
X while (bytes) {
X n = write(fd, buf, bytes);
X if (n > 0) {
X bytes -= n;
X buf += n;
X continue;
X }
X if (errno == EINTR)
X continue;
X if (errno == EWOULDBLOCK) {
X fd_set fd_wr;
X fd_set fd_ex;
X FD_ZERO(&fd_wr);
X FD_ZERO(&fd_ex);
X FD_SET(fd, &fd_wr);
X FD_SET(fd, &fd_ex);
X select(fd+1, NULL, &fd_wr, &fd_ex, NULL);
X continue;
X }
X if (errno == EPIPE)
X return;
X dneterror("gwrite");
X }
X}
X
SHAR_EOF
echo "extracting dnet/internal.c"
sed 's/^X//' << \SHAR_EOF > dnet/internal.c
X
X/*
X * INTERNAL.C
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X *
X * Usually SCMD_OPEN requests attempt to connect() to the UNIX
X * domain socket of the server. However, some 'ports' are designated
X * as internal to DNET. They reside here.
X *
X * -IALPHATERM
X */
X
X#include "dnet.h"
X#include "../server/servers.h"
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <sys/resource.h>
X#include <sys/uio.h>
X#include <strings.h>
X
Xextern char *getenv();
X
Xisinternalport(port)
Xuword port;
X{
X if (port == PORT_IALPHATERM)
X return(1);
X return(0);
X}
X
Xiconnect(ps, port)
Xint *ps;
Xuword port;
X{
X if (port == PORT_IALPHATERM)
X return(ialphaterm_connect(ps, port));
X return(-1);
X}
X
Xialphaterm_connect(pmaster)
Xint *pmaster;
X{
X struct sgttyb sg;
X struct tchars tc;
X struct ltchars ltc;
X#ifdef TIOCGSIZE
X struct ttysize ts;
X#else
X#ifdef TIOCGWINSZ
X struct winsize ws;
X#endif
X#endif
X int lmode;
X int fdmaster;
X int fdslave;
X int pid;
X char *slavename;
X
X ioctl(0, TIOCGETP, (char *)&sg);
X ioctl(0, TIOCGETC, (char *)&tc);
X ioctl(0, TIOCGLTC, (char *)<c);
X ioctl(0, TIOCLGET, (char *)&lmode);
X#ifdef TIOCGSIZE
X ioctl(0, TIOCGSIZE, &ts);
X#else
X#ifdef TIOCGWINSZ
X ioctl(0, TIOCGWINSZ, &ws);
X#endif
X#endif
X
X sg.sg_flags &= ~(RAW);
X sg.sg_flags |= ECHO;
X#ifdef TIOCGSIZE
X ts.ts_lines = 23;
X ts.ts_cols = 77;
X#else
X#ifdef TIOCGWINSZ
X ws.ws_row = 23;
X ws.ws_col = 77;
X#endif
X#endif
X
X if (DDebug)
X fprintf(stderr, "PTY openning internal pty\n");
X if (openpty(&fdmaster, &fdslave, &slavename) >= 0) {
X if (DDebug)
X fprintf(stderr, "PTY open successfull\n");
X if ((pid = fork()) == NULL) {
X int i;
X setenv("DNET=", "IALPHATERM");
X setuid(getuid());
X signal(SIGHUP, SIG_DFL);
X signal(SIGINT, SIG_DFL);
X signal(SIGQUIT, SIG_DFL);
X signal(SIGTERM, SIG_DFL);
X signal(SIGCHLD, SIG_DFL);
X signal(SIGTSTP, SIG_IGN);
X ioctl(open("/dev/tty", 2), TIOCNOTTY, NULL);
X close(open(slavename, 0));
X dup2(fdslave, 0);
X dup2(0, 1);
X dup2(0, 2);
X for (i = 3; i < 256; ++i)
X close(i);
X ioctl(0, TIOCSETN, &sg);
X ioctl(0, TIOCSETC, &tc);
X ioctl(0, TIOCSLTC, <c);
X ioctl(0, TIOCLSET, &lmode);
X#ifdef TIOCSSIZE
X ioctl(0, TIOCSSIZE, &ts);
X#else
X#ifdef TIOCSWINSZ
X ioctl(0, TIOCSWINSZ, &ws);
X#endif
X#endif
X {
X char *shell = getenv("SHELL");
X char *home = getenv("HOME");
X if (!shell)
X shell = "/bin/sh";
X if (!home)
X home = ".";
X chdir(home);
X execl(shell, "-fshell", NULL);
X perror(shell);
X }
X _exit(1);
X }
X if (pid > 0) {
X *pmaster = fdmaster;
X close(fdslave);
X if (DDebug)
X fprintf(stderr, "PTY OPEN OK.2\n");
X return(1);
X }
X close(fdmaster);
X close(fdslave);
X if (DDebug)
X fprintf(stderr, "PTY OPEN FAILURE.1\n");
X }
X if (DDebug)
X fprintf(stderr, "PTY OPEN FAILURE.2\n");
X return(-1);
X}
X
Xopenpty(pfdm, pfds, pnames)
Xint *pfdm;
Xint *pfds;
Xchar **pnames;
X{
X static char ptcs[] = { "0123456789abcdef" };
X static char plate[] = { "/dev/ptyxx" };
X struct stat stat;
X int i;
X int j;
X
X for (i = 'p';; ++i) {
X plate[8] = i;
X plate[9] = ptcs[0];
X if (lstat(plate, &stat) < 0)
X break;
X for (j = 0; ptcs[j]; ++j) {
X plate[9] = ptcs[j];
X plate[5] = 'p';
X if ((*pfdm = open(plate, O_RDWR)) >= 0) {
X plate[5] = 't';
X if ((*pfds = open(plate, O_RDWR)) >= 0) {
X *pnames = plate;
X if (DDebug)
X fprintf(stderr, "PTY FOUND %s\n", *pnames);
X return(1);
X }
X close(*pfdm);
X }
X }
X }
X return(-1);
X}
X
Xisetrows(fd, rows)
X{
X#ifdef TIOCSSIZE
X struct ttysize ts;
X if (ioctl(fd, TIOCGSIZE, &ts) >= 0) {
X ts.ts_lines = rows;
X ioctl(fd, TIOCSSIZE, &ts);
X }
X#else
X#ifdef TIOCSWINSZ
X struct winsize ws;
X if (ioctl(fd, TIOCGWINSZ, &ws) >= 0) {
X ws.ws_row = rows;
X ioctl(fd, TIOCSWINSZ, &ws);
X }
X#endif
X#endif
X}
X
Xisetcols(fd, cols)
X{
X#ifdef TIOCSSIZE
X struct ttysize ts;
X if (ioctl(fd, TIOCGSIZE, &ts) >= 0) {
X ts.ts_cols = cols;
X ioctl(fd, TIOCSSIZE, &ts);
X }
X#else
X#ifdef TIOCSWINSZ
X struct winsize ws;
X if (ioctl(fd, TIOCSWINSZ, &ws) >= 0) {
X ws.ws_col = cols;
X ioctl(fd, TIOCSWINSZ, &ws);
X }
X#endif
X#endif
X}
X
SHAR_EOF
echo "extracting dnet/globals.c"
sed 's/^X//' << \SHAR_EOF > dnet/globals.c
X
X/*
X * GLOBALS.C
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X */
X
X#include "dnet.h"
X
Xint Enable_Abort;
X
Xlong USecPerByte = 1000;/* for 9600 baud.. should really set properly */
Xint DNet_fd = -1; /* Master listen socket */
XPKT Pkts[9]; /* data buffers for packets */
XPKT *Raux = Pkts+8; /* next packet in */
Xubyte WCBuf[64];
XPKT *RPak[4] = { Pkts+0,Pkts+1,Pkts+2,Pkts+3 };
XPKT *WPak[4] = { Pkts+4,Pkts+5,Pkts+6,Pkts+7 };
XCHAN Chan[MAXCHAN]; /* Channels */
XLIST TxList; /* For pending SCMD_DATA reqs. */
Xfd_set Fdread;
Xfd_set Fdwrite;
Xfd_set Fdexcept;
Xvoid (*Fdstate[FD_SETSIZE])();
Xubyte Fdperm[FD_SETSIZE];
Xuword FdChan[FD_SETSIZE];
Xubyte RcvBuf[RCVBUF];
Xuword RcvData;
Xuword RExpect;
Xubyte RTimedout;
Xubyte WTimedout;
Xuword WChan; /* Read and Write channels */
Xuword RChan;
Xuword RPStart;
Xuword WPStart;
Xuword WPUsed;
Xuword RState;
Xuword Rto_act, Wto_act;
Xubyte DDebug;
Xubyte DidWrite;
Xubyte Restart;
Xubyte DeldQuit;
Xulong NumCon;
X
X
SHAR_EOF
echo "extracting dnet/files.c"
sed 's/^X//' << \SHAR_EOF > dnet/files.c
X
X/*
X * FILES.C
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X *
X * handles actions on a per file descriptor basis, including accepting
X * new connections, closing old connections, and transfering data
X * between connections.
X */
X
X#include "dnet.h"
X
Xextern void do_localopen(), do_connect(), do_open1(), do_openwait(), do_open();
X
X/*
X * new connection over master port... open request. read two byte port
X * number, allocate a channel, and send off to the remote
X */
X
Xvoid
Xdo_localopen(n, fd)
X{
X struct sockaddr sa;
X int addrlen = sizeof(sa);
X int s;
X uword chan;
X
X if (DDebug)
X fprintf(stderr, "DO_LOCALOPEN %ld %ld\n", n, fd);
X while ((s = accept(fd, &sa, &addrlen)) >= 0) {
X chan = alloc_channel();
X fcntl(s, F_SETFL, FNDELAY);
X if (DDebug)
X fprintf(stderr, " ACCEPT: %ld on channel %ld ", s, chan);
X if (chan == 0xFFFF) {
X ubyte error = 1;
X gwrite(s, &error, 1);
X close(s);
X if (DDebug)
X fprintf(stderr, "(no channels)\n");
X continue;
X }
X Fdstate[s] = do_open1;
X FdChan[s] = chan;
X FD_SET(s, &Fdread);
X FD_SET(s, &Fdexcept);
X Chan[chan].fd = s;
X Chan[chan].state = CHAN_LOPEN;
X if (DDebug)
X fprintf(stderr, "(State = CHAN_LOPEN)\n");
X }
X}
X
Xvoid
Xdo_open1(n, fd)
X{
X uword port;
X char trxpri[2];
X uword chan = FdChan[fd];
X COPEN co;
X int n;
X
X if (DDebug)
X fprintf(stderr, "DO_OPEN %ld %ld on channel %ld ", n, fd, chan);
X for (;;) {
X n = read(fd, &port, 2);
X if (n < 0) {
X if (errno == EINTR)
X continue;
X if (errno == EWOULDBLOCK)
X return;
X }
X read(fd, trxpri, 2);
X if (n != 2)
X dneterror("do_open1: unable to read 2 bytes");
X break;
X }
X if (DDebug)
X fprintf(stderr, "Port %ld\n", port);
X co.chanh = chan >> 8;
X co.chanl = chan;
X co.porth = port >> 8;
X co.portl = port;
X co.error = 0;
X co.pri = trxpri[1];
X Chan[chan].port = port;
X Chan[chan].pri = 126;
X WriteStream(SCMD_OPEN, &co, sizeof(co), chan);
X Chan[chan].pri = trxpri[0];
X Fdstate[fd] = do_openwait;
X if (DDebug)
X fprintf(stderr, " Newstate = openwait\n");
X}
X
Xvoid
Xdo_openwait(n, fd)
X{
X ubyte buf[32];
X if (DDebug)
X fprintf(stderr, "************ ERROR DO_OPENWAIT %ld %ld\n", n, fd);
X n = read(fd, buf, 32);
X if (DDebug) {
X fprintf(stderr, " OPENWAIT, READ %ld bytes\n", n);
X if (n < 0)
X perror("openwait:read");
X }
X}
X
Xvoid
Xdo_open(nn, fd)
X{
X extern void nop();
X char buf[256];
X uword chan = FdChan[fd];
X int n;
X
X n = read(fd, buf, sizeof(buf));
X if (DDebug) {
X fprintf(stderr, "DO_OPEN %ld %ld, RECEIVE DATA on chan %ld (%ld by)\n",
X nn, fd, chan, n);
X fprintf(stderr, " fd, chanfd %ld %ld\n", fd, Chan[chan].fd);
X if (n < 0)
X perror("open:read");
X }
X if (n == 0 || nn == 2) { /* application closed / exception cond */
X CCLOSE cc;
X
X if (DDebug)
X fprintf(stderr, " DO_OPEN: REMOTE EOF, channel %d\n", chan);
X
X cc.chanh = chan >> 8;
X cc.chanl = chan;
X WriteStream(SCMD_CLOSE, &cc, sizeof(CCLOSE), chan);
X Chan[chan].state = CHAN_CLOSE;
X Chan[chan].flags |= CHANF_LCLOSE;
X if (Chan[chan].flags & CHANF_RCLOSE) {
X ;
X /* should never happen
X int fd = Chan[chan].fd;
X Chan[chan].state = CHAN_FREE;
X Chan[chan].fd = -1;
X Fdstate[fd] = nop;
X FD_CLR(fd, &Fdread);
X FD_CLR(fd, &Fdexcept);
X close(fd);
X */
X } else {
X FD_CLR(fd, &Fdread);
X FD_CLR(fd, &Fdexcept);
X }
X }
X if (n > 0) {
X WriteStream(SCMD_DATA, buf, n, chan);
X }
X}
X
SHAR_EOF
echo "extracting dnet/dnet.h"
sed 's/^X//' << \SHAR_EOF > dnet/dnet.h
X
X/*
X * DNET.H
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X */
X
X#include <sys/types.h>
X#include <sys/ioctl.h>
X#include <sys/socket.h>
X#include <sys/time.h>
X#include <sys/file.h>
X
X/* V2.01 */
X#include <sys/param.h>
X#include <pwd.h>
X
X#include <signal.h>
X#include <stdio.h>
X#include <errno.h>
X#ifndef FD_SETSIZE
X#define FD_SETSIZE (sizeof(struct fd_set) * 8)
X#endif
X#ifndef NFDBITS
X#define NFDBITS 32
X#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
X#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
X#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
X#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
X#endif
X#ifndef sigmask
X#define sigmask(m) (1 << ((m)-1))
X#endif
X
X#ifndef LASTTRYDNETSERVERS
X#define LASTTRYDNETSERVERS "/usr/local/lib/dnet/dnet.servers"
X#endif
X
Xstruct Node {
X struct Node *ln_Succ;
X struct Node *ln_Pred;
X};
X
Xstruct List {
X struct Node *lh_Head;
X struct Node *lh_Tail;
X struct Node *lh_TailPred;
X};
X
X
Xtypedef unsigned char ubyte;
Xtypedef unsigned short uword;
Xtypedef unsigned long ulong;
X
Xtypedef struct List LIST;
Xtypedef struct Node NODE;
X
X#include "channel.h"
X
X#define PKT struct _PKT
X#define XIOR struct _XIOR
X
X#define EMPTY 0 /* empty (sent) */
X#define READY 1 /* data ready (not sent yet) */
X#define RCVBUF 4096
X
X#define MAXCHAN 128 /* Max # of channels supported */
X#define SYNC 0xFF /* SYNC character */
X#define WTIME 2000000 /* in micro seconds (expect ack) */
X#define RTIME 1000000 /* in micro seconds (read to) */
X#define MAXPKT 200 /* maximum packet size (data area) */
X#define MINPKT 32 /* minimum packet size (data area) for purposes */
X /* of determining the dynamic maximum packet size*/
X /* only. Actual minimum is, of course, 1 byte */
X
X#define OVERHEAD 7 /* for packets with data */
X
XXIOR {
X NODE io_Node;
X ubyte *io_Data;
X ulong io_Length;
X ulong io_Actual;
X uword io_Channel;
X ubyte io_Command;
X ubyte io_Error;
X char io_Pri;
X};
X
XPKT {
X uword iolength; /* send: length of packet, recv: length of data */
X ubyte state; /* EMPTY, READY */
X
X ubyte sync; /* THE PACKET */
X ubyte ctl;
X ubyte cchk;
X ubyte lenh;
X ubyte lenl;
X ubyte data[MAXPKT+2];
X};
X
X /*
X * In receiving a packet the receiver can be in one of these
X * states.
X */
X
X#define RS_SYNC 0 /* Waiting for sync */
X#define RS_CTL 1 /* Waiting for command */
X#define RS_CCHK 2 /* Waiting for check byte */
X#define RS_LEN1 3 /* Waiting for MSB length byte */
X#define RS_LEN2 4 /* Waiting for LSB length byte */
X#define RS_DATA 5 /* Waiting for data & checksum */
X
X /*
X * The low level protocol generates packets. This is used
X * for error checking, data sequencing, retries, restart, etc...
X * The packet format is:
X *
X * SYNC sss0xccc CHK
X * SYNC sss1xccc CHK nnnnnnnn nnnnnnnn [DATA] CHK2
X * msb lsb
X *
X * sss = sequence #
X * B4 = packet contains data
X * B3 = reserved (may be used to extend the command set)
X * ccc = PKF_?????
X *
X * NOTE that the data length nnn..nn is not checked with either
X * CHK or CHK2 . The protocol will determine if the length
X * is reasonable (< MAXPKT) and then try to read that many
X * bytes. The CHK will obviously fail if the length was
X * incorrect.
X */
X
X#define PKF_SEQUENCE 0xE0 /* Sequence # */
X#define PKF_DATA 0x10 /* 1-65535 bytes */
X#define PKF_RESERVED 0x08 /* reserved bit */
X#define PKF_MASK 0x07 /* command mask */
X
X#define PKCMD_WRITE 1 /* A DATA packet */
X#define PKCMD_CHECK 2 /* Request ACK or NAK for win */
X#define PKCMD_ACK 3 /* ACK a window */
X#define PKCMD_NAK 4 /* NAK a window */
X#define PKCMD_RESTART 5 /* RESTART dnet. (new) */
X#define PKCMD_ACKRSTART 6 /* ACK a restart (new) */
X#define PKCMD_RESERVE3 7
X
X /*
X * All channel multiplexing, channel commands, etc... is encoded
X * within a PKCMD_WRITE packet.
X *
X * Channel commands are characterized by a one byte control
X * field and up to 7 bytes of data. The control field format
X * is: 10cccnnn [DATA] ccc = SCMD_??
X * nnn = # additional data bytes
X */
X
X#define SCMD_SWITCH 0x00 /* switch active channel # */
X#define SCMD_OPEN 0x01 /* open a channel */
X#define SCMD_CLOSE 0x02 /* close a channel */
X#define SCMD_ACKCMD 0x03 /* ack an open/close request */
X#define SCMD_EOFCMD 0x04 /* Reof or Weof */
X#define SCMD_QUIT 0x05 /* QUIT dnet */
X#define SCMD_IOCTL 0x06 /* channel ioctl (new),PTY sup */
X#define SCMD_RESERVE1 0x07
X
X /*
X * Stream data is characterized by the following format:
X *
X * msb lsb
X * 11nnnnnn nnnnnnnn [128-16383 bytes DATA]
X * 0nnnnnnn [0-127 bytes DATA]
X *
X * NOTE: 11000000 0ccccccc nnnnnnnn reserved for furture ext. of
X * SCMD commands.
X */
X
X#define SCMD_DATA 0x08 /* stream command, DATA (dummy ID) */
X
X /*
X * Each channel can be in one of several states.
X */
X
X#define CHAN_FREE 0x01 /* free channel */
X#define CHAN_ROPEN 0x02 /* remote open, wait port msg */
X#define CHAN_LOPEN 0x03 /* local open, wait reply */
X#define CHAN_OPEN 0x04 /* channel open */
X#define CHAN_CLOSE 0x05 /* one side of channel closed */
X
X#define CHANF_ROK 0x01 /* remote hasn't EOF'd us yet */
X#define CHANF_WOK 0x02 /* remote will accept data */
X#define CHANF_LCLOSE 0x04 /* channel closed on our side */
X#define CHANF_RCLOSE 0x08 /* channel closed on rem side */
X
Xextern ubyte *RemHead();
Xextern ubyte *malloc();
Xextern char *getenv();
X
X#ifndef NOEXT
Xextern long USecPerByte;
Xextern int DNet_fd;
Xextern PKT Pkts[9];
Xextern ubyte WCBuf[64];
Xextern PKT *RPak[4];
Xextern PKT *WPak[4];
Xextern CHAN Chan[MAXCHAN];
Xextern LIST TxList; /* For pending DNCMD_WRITE reqs. */
Xextern fd_set Fdread;
Xextern fd_set Fdwrite;
Xextern fd_set Fdexcept;
Xextern void (*Fdstate[FD_SETSIZE])();
Xextern ubyte Fdperm[FD_SETSIZE];
Xextern uword FdChan[FD_SETSIZE];
Xextern ubyte RcvBuf[RCVBUF];
Xextern ubyte RTimedout, WTimedout;
Xextern uword Rto_act, Wto_act;
Xextern uword RcvData;
Xextern uword RExpect;
Xextern uword RChan;
Xextern uword WChan;
Xextern uword RPStart;
Xextern uword WPStart;
Xextern uword WPUsed;
Xextern uword RState;
Xextern ubyte DDebug;
Xextern ubyte DidWrite;
Xextern ubyte Restart;
Xextern ubyte DeldQuit;
Xextern ulong NumCon;
X
Xextern int errno;
X
X#endif
X
SHAR_EOF
echo "extracting dnet/dnet.c"
sed 's/^X//' << \SHAR_EOF > dnet/dnet.c
X
X/*
X * DNET.C
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X *
X * Handles action on all active file descriptors and dispatches
X * to the proper function in FILES.C
X *
X */
X
X#include "dnet.h"
X#include <sys/wait.h>
X#include <sys/resource.h>
X
Xhandle_child()
X{
X union wait stat;
X struct rusage rus;
X while (wait3(&stat, WNOHANG, &rus) > 0);
X}
X
Xchar *
Xshowselect(ptr)
Xfd_set *ptr;
X{
X static char buf[FD_SETSIZE+32];
X short i;
X
X for (i = 0; i < FD_SETSIZE; ++i) {
X buf[i] = (FD_ISSET(i, ptr)) ? '1' : '0';
X }
X buf[i] = 0;
X return(buf);
X}
X
X
Xloganddie()
X{
X fflush(stderr);
X fprintf(stderr, "\nHUPSIGNAL\n");
X perror("HUP, last error:");
X fprintf(stderr, "Last select return:\n");
X fprintf(stderr, " %s\n", showselect(&Fdread));
X fprintf(stderr, " %s\n", showselect(&Fdwrite));
X fprintf(stderr, " %s\n", showselect(&Fdexcept));
X fprintf(stderr, "RcvData = %ld\n", RcvData);
X fprintf(stderr, "RChan/WChan = %ld/%ld\n", RChan, WChan);
X fprintf(stderr, "RPStart = %ld\n", RPStart);
X fprintf(stderr, "WPStart = %ld\n", WPStart);
X fprintf(stderr, "WPUsed = %ld\n", WPUsed);
X fprintf(stderr, "RState = %ld\n", RState);
X fflush(stderr);
X kill(0, SIGILL);
X exit(1);
X}
X
X#define SASIZE(sa) (sizeof(sa)-sizeof((sa).sa_data)+strlen((sa).sa_data))
X
Xmain(ac,av)
Xchar *av[];
X{
X long sink_mask, dnet_mask;
X long mark = 0;
X ubyte notdone;
X char local_dir[MAXPATHLEN];
X struct passwd pw_info;
X extern void RcvInt();
X
X if (getenv("DNETDIR")) {
X strcpy(local_dir, getenv("DNETDIR"));
X if (chdir(local_dir)) {
X fprintf(stderr, "Unable to chdir to DNETDIR: %s\n", local_dir);
X exit(1);
X }
X freopen("DNET.LOG", "w", stderr);
X } else {
X pw_info = *getpwuid(getuid());
X strcpy(local_dir, pw_info.pw_dir);
X strcat(local_dir, "/.dnet");
X if (chdir(local_dir)) {
X mkdir(local_dir, 0700);
X if (chdir(local_dir)) {
X fprintf(stderr, "Unable to create dir %s\n", local_dir);
X exit(1);
X }
X }
X freopen("DNET.LOG", "w", stderr);
X }
X fprintf(stderr, "DNet startup\n");
X fprintf(stderr, "Log file placed in %s\n", local_dir);
X fflush(stderr);
X
X signal(SIGINT, SIG_IGN);
X signal(SIGPIPE, SIG_IGN);
X signal(SIGQUIT, SIG_IGN);
X signal(SIGCHLD, handle_child);
X signal(SIGHUP, loganddie);
X
X bzero(Pkts,sizeof(Pkts));
X setlistenport("");
X
X {
X register short i;
X for (i = 1; i < ac; ++i) {
X register char *ptr = av[i];
X if (*ptr != '-') {
X DDebug = 1;
X fprintf(stderr, "Debug mode on\n");
X continue;
X }
X switch(*ptr) {
X case 'B':
X USecPerByte = atoi(ptr+1) / 10; /* bytes per second */
X USecPerByte = 1000000 / USecPerByte;
X fprintf(stderr, "Assuming about %ld uS/byte for timeout calc\n",
X USecPerByte
X );
X break;
X default:
X fprintf(stderr, "Unknown option: %c\n", *ptr);
X printf("Unknown option: %c\n", *ptr);
X exit(1);
X }
X }
X }
X
X NewList(&TxList);
X
X Fdperm[0] = 1;
X Fdstate[0] = RcvInt;
X FD_SET(0, &Fdread);
X FD_SET(0, &Fdexcept);
X
X fprintf(stderr, "DNET RUNNING, Listenfd=%ld\n", DNet_fd);
X NetOpen(); /* initialize network and interrupt driven read */
X TimerOpen(); /* initialize timers */
X
X do_netreset();
X do_restart();
X
X notdone = 1;
X while (notdone) {
X /*
X * MAIN LOOP. select() on all the file descriptors. Set the
X * timeout to infinity (NULL) normally. However, if there is
X * a pending read or write timeout, set the select timeout
X * to 2 seconds in case they timeout before we call select().
X * (i.e. a timing window). OR, if we are in the middle of a
X * read, don't use descriptor 0 and timeout according to
X * the expected read length, then set the descriptor as ready.
X */
X
X fd_set fd_rd;
X fd_set fd_wr;
X fd_set fd_ex;
X struct timeval tv, *ptv;
X int err;
X
X fd_rd = Fdread;
X fd_wr = Fdwrite;
X fd_ex = Fdexcept;
X
X tv.tv_sec = 0; /* normally wait forever for an event */
X tv.tv_usec= 0;
X ptv = NULL;
X if ((Rto_act || Wto_act)) { /* unless timeout pending */
X ptv = &tv;
X tv.tv_sec = 2;
X }
X
X /* ... or expecting data (don't just wait for one byte).
X *
X * This is an attempt to reduce the CPU usage for the process.
X * If we are expecting data over the serial line, then don't
X * return from the select() even if data is available, but
X * wait for the timeout period indicated before reading the
X * data. Don't wait more than 64 byte times or we may loose
X * some data (the silo's are only so big.. like 128 bytes).
X *
X * Currently, USecPerByte is not set properly (set for 9600 baud)
X */
X
X if (RExpect) {
X ptv = &tv;
X tv.tv_usec= USecPerByte * ((RExpect < 64) ? RExpect : 64);
X tv.tv_sec = 0;
X FD_CLR(0, &fd_rd);
X }
X err = select(FD_SETSIZE, &fd_rd, &fd_wr, &fd_ex, ptv);
X if (RExpect) {
X FD_SET(0, &fd_rd); /* pretend data ready */
X }
X if (DDebug)
X fprintf(stderr, "SERR %ld %ld %08lx %08lx\n",
X err, errno, RExpect, ptv
X );
X
X if (RTimedout) {
X RTimedout = 0;
X do_rto();
X mark = 0;
X }
X if (WTimedout) {
X WTimedout = 0;
X do_wto();
X }
X if (err < 0) {
X if (errno == EBADF) {
X perror("select");
X dneterror(NULL);
X }
X } else {
X register short i;
X register short j;
X register long mask;
X
X for (i = 0; i < FD_SETSIZE/NFDBITS; ++i) {
X if (mask = fd_ex.fds_bits[i]) {
X for (j = i * NFDBITS; mask; (mask >>= 1),(++j)) {
X if (mask & 1)
X (*Fdstate[j])(2,j);
X }
X }
X if (mask = fd_wr.fds_bits[i]) {
X for (j = i * NFDBITS; mask; (mask >>= 1),(++j)) {
X if (mask & 1)
X (*Fdstate[j])(1,j);
X }
X }
X if (mask = fd_rd.fds_bits[i]) {
X for (j = i * NFDBITS; mask; (mask >>= 1),(++j)) {
X if (mask & 1)
X (*Fdstate[j])(0,j);
X }
X }
X }
X }
X if (RcvData != mark)
X mark = do_rnet();
X do_wupdate();
X do_wnet();
X }
X dneterror(NULL);
X}
X
Xvoid
Xnop()
X{
X}
X
Xdo_netreset()
X{
X register short i;
X register CHAN *ch;
X for (i = 0; i < FD_SETSIZE; ++i) {
X if (!Fdperm[i])
X Fdstate[i] = nop;
X }
X for (i = 0, ch = Chan; i < MAXCHAN; ++i, ++ch) {
X switch(ch->state) {
X case CHAN_OPEN:
X case CHAN_LOPEN: /* pending on network */
X case CHAN_CLOSE:
X if (ch->fd >= 0) {
X FD_CLR(ch->fd, &Fdread);
X FD_CLR(ch->fd, &Fdexcept);
X Fdstate[ch->fd] = nop;
X close(ch->fd);
X ch->fd = -1;
X ch->state = CHAN_FREE;
X ch->flags = 0;
X --NumCon;
X }
X ClearChan(&TxList, i, 1);
X break;
X }
X }
X RPStart = 0;
X WPStart = 0;
X WPUsed = 0;
X RState = 0;
X RChan = 0;
X WChan = 0;
X}
X
Xdo_restart()
X{
X static ubyte buf[3] = { SYNC, PKCMD_RESTART, (SYNC<<1)^PKCMD_RESTART };
X Restart = 1;
X NetWrite(buf, sizeof(buf), 1);
X WTimeout(WTIME);
X}
X
Xsetlistenport(remotehost)
Xchar *remotehost;
X{
X static struct sockaddr sa[2];
X int s;
X extern void do_localopen();
X
X if (DNet_fd >= 0) {
X unlink(sa[0].sa_data);
X Fdstate[DNet_fd] = nop;
X Fdperm[DNet_fd] = 0;
X FD_CLR(DNet_fd, &Fdread);
X FD_CLR(DNet_fd, &Fdexcept);
X close(DNet_fd);
X }
X setenv("DNETHOST=", remotehost);
X sprintf(sa[0].sa_data, "DNET.%s", remotehost);
X unlink(sa[0].sa_data);
X sa[0].sa_family = AF_UNIX;
X
X s = socket(PF_UNIX, SOCK_STREAM, 0);
X fcntl(s, F_SETOWN, getpid());
X fcntl(s, F_SETFL, FNDELAY);
X if (bind(s, &sa[0], SASIZE(sa[0])) < 0) {
X perror("bind");
X exit(1);
X }
X if (listen(s, 5) < 0) {
X unlink(sa[0].sa_data);
X perror("listen");
X exit(1);
X }
X DNet_fd = s;
X Fdstate[DNet_fd] = do_localopen;
X Fdperm[DNet_fd] = 1;
X FD_SET(DNet_fd, &Fdread);
X FD_SET(DNet_fd, &Fdexcept);
X}
X
SHAR_EOF
echo "extracting dnet/Makefile"
sed 's/^X//' << \SHAR_EOF > dnet/Makefile
X
X# THE DNET DRIVER, UNIX END
X#
X# DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X#
X# the BIN should be placed in your path for ease of use. DNET uses
X# UNIX level sockets allowing multiple users on a system to run it
X# independantly. You should make a special directory (Example: .DNET)
X# and then setenv DNETDIR ~/.DNET/ ... all clients and servers will
X# use the enviroment variable to find/create the UNIX level sockets.
X
XBIN = ../bin
XOBJS = dnet.o control.o files.o globals.o net.o subs.o internal.o
X
X
X$(BIN)/dnet: $(OBJS)
X cc $(OBJS) -o $(BIN)/dnet
X
Xclean:
X rm -f *.o make.out
X
SHAR_EOF
echo "extracting dnet/MODS"
sed 's/^X//' << \SHAR_EOF > dnet/MODS
X
Xnet.c: notion of reply expected added to NetWrite()
Xdnet.c: select modified. On error still attempt write ops
X
SHAR_EOF
echo "extracting dnet.servers"
sed 's/^X//' << \SHAR_EOF > dnet.servers
X
X8192 ~/src/dnet.unix/bin/scopy ~
X8193 ~/src/dnet.unix/bin/sshell ~
X8197 ~/src/dnet.unix/bin/sloadav ~
X8201 ~/src/dnet.unix/bin/sgcopy ~
X
SHAR_EOF
if `test ! -d doc`
then
mkdir doc
echo "mkdir doc"
fi
echo "extracting doc/history"
sed 's/^X//' << \SHAR_EOF > doc/history
X
X V1.00 sometime in 1987
X First release
X
X V1.20 sometime in 1988
X Fixes to the first release
X
X V2.00 1 March 1989
X
X Major fixes, additions, and other items.
X
X
X
SHAR_EOF
echo "extracting doc/dnet.doc"
sed 's/^X//' << \SHAR_EOF > doc/dnet.doc
X
XUNIX/DNET
X
X DNET [debug]
X
X Run the DNET protocol on descriptor 0. If the enviroment variable
X DNETDIR exists, DNET will create the rendezvous sockets in the
X specified directory (DNETDIR must have a hanging slash on it),
X otherwise the current directory is used.
X
X DNET also opens a log file (DNET.LOG) in the directory. If the debug
X option is given, DNET writes gobs of debugging information to the log.
X
X Descriptor 0 may be a tty or socket.
X
X To allow DNET to startup servers on demand, the file "dnet.servers"
X must exist in the rendezvous directory.
X
X -Matt
X
SHAR_EOF
echo "extracting doc/putfiles.doc"
sed 's/^X//' << \SHAR_EOF > doc/putfiles.doc
XUNIX/PUTFILES
XAMIGA/PUTFILES
X
X PUTFILES [-dDESTDIR] file/dir file/dir file/dir ..
X
X File transfer client. Transfer the specified files and or directories
X to the destination directory on the remote machine. For instance:
X
X unix: putfiles -dram: charlie.txt /usr/include
X
X *places the file charlie.txt as ram:charlie.txt, and places the
X directory structure /usr/include as ram:include/(whatever).
X
X The default destination directory depends on the remote host. If the
X destination is an Amiga, the default is DF0: (so you probably always
X want to specify a -d switch). On the UNIX end, the default is whatever
X is set in the file dnet.servers
X
X Currently, no file compression is done. I also hope to add
X semi-automatic crash recovery (continue download where you left off
X after a crash), though it should be noted that it is very difficult
X to crash DNET with random modem noise.
X
SHAR_EOF
echo "extracting doc/dsoc.doc"
sed 's/^X//' << \SHAR_EOF > doc/dsoc.doc
X
X
XUNIX/DSOC
X
X
XDSOC [port#]
X
X (default: 8196 = AMIGSHELL (CLI window))
X
X Connect to the remote port but keep the TTY in COOKED mode (normal).
X The connection will be terminated by killing the process on the UNIX
X end or typing ^C. NOTE THAT ^C KILLS DSOC AND IS NOT SENT THROUGH TO
X THE REMOTE CLI.
X
X The default port accesses the SCLI server on the Amiga end, which
X starts up a CLI. Things work properly only if *MY* PIPE: device is
X installed on the Amiga. Things close down properly only if you
X have a CLI prompt when you exit DSOC.
X
X The SCLI server currently handles only one connection at a time.
X
SHAR_EOF
echo "extracting doc/dnetlib.doc"
sed 's/^X//' << \SHAR_EOF > doc/dnetlib.doc
X
XUNIX/DNETLIB
X
X UNIX END DNET LIBRARY INTERFACE
X
X See the server source for good examples of usage.
X
Xlong private;
Xuword port
Xchar *buf;
Xint fd;
Xint res1..5, bytes
Xchar pri;
Xlong val68, valvax;
X
Xprivate = DListen(port) listen on a port (server)
X fd = DAccept(private) accept a connection (server)
X DNAAccept(private) don't accept a conn.(server)
X fd = DOpen(host, port, txpri, rxpri) open a remote connection (client)
X res1 = read(fd, buf, bytes) standard unix read()
X res2 = gread(fd, buf, bytes) (see below)
X res3 = ggread(fd, buf, bytes) (see below)
X res4 = write(fd, buf, bytes) standard unix write()
X res5 = gwrite(fd, buf, bytes) (see below)
X close(fd);
X
X val68 = ntohl68(valvax) convert to and from MC68000 longword format.
X valvax= htonl68(val68)
X
X
XDListen() sets up a UNIX domain socket in the current directory unless
X another is specified by the DNETDIR enviroment variable.
X Returns a private structure pointer or NULL on error.
X
X This call will override any existing server for the port in
X the directory permanently. It does not cause an existing
X server to exit, however, and you should be careful to kill
X old servers before starting new ones. See the source for a
X template of correct server code.
X
XDAccept() Accepts a new connection on the port. Returns a file
X descriptor or a negative value. This call will block.
X
XDOpen() Attempt to connect to a port on the remote machine. Returns
X a file descriptor or a negative value. The error is either
X due to not finding DNET's master port (DNET must be running),
X or the remote server not running.
X
X This call looks in the current directory for the master
X socket unless another is specified by the DNETDIR enviroment
X variable.
X
X Two priorities are specified. One for sending, and one for
X receiving data. A priority is a value -127 to 126 inclusive,
X with 126 the highest priority. Normally, priorities range
X from -80 (file transfers) to +20 (terminal window).
X
XDEof() Send an EOF without closing the connection. Currently doesn't
X work worth shit, so don't use it.
X
Xwrite() Standard UNIX write call. But we are dealing with a socket
X here, so one must be careful of the return value. (1) WRITE()
X may not return the # bytes requested to write, but less,
X (2) WRITE() may return a negative value indicating an error or
X that it was interrupted or that it would have blocked (if you
X have got non-blocking IO setup). (3) WRITE() returns 0 on
X socket EOF.
X
Xgwrite() This call will write all the bytes specified, whether the
X socket is non-blocking or not. It handles restarting the
X WRITE() call on EINTR and properly handles EWOULDBLOCK.
X
X It returns the number bytes requested or fewer on error. If
X fewer bytes are returned you should close the socket and exit.
X
Xread() Standard UNIX read call. But we are still dealing with a
X socket here and anything might happen. READ() can return fewer
X than the number of bytes requested, 0 on EOF, or a negative
X number indicating various errors.
X
Xgread() GREAD() handles retrying if the EINTR error occurs. GREAD()
X blocks until at least one character is received (or EOF), and
X does this even if the socket is marked non-blocking. GREAD()
X returns 0 on EOF/ERROR.
X
Xggread() GGREAD() not only retries on EINTR, but will block until ALL
X the requested bytes are read in, even if the socket is marked
X non-blocking. GGREAD() returns -1 on EOF/ERROR. You can also
X tell if an EOF/ERROR occured if fewer than the requested
X number of bytes are read.
X
SHAR_EOF
echo "extracting doc/draw.doc"
sed 's/^X//' << \SHAR_EOF > doc/draw.doc
X
XUNIX/DRAW
X
X
XDRAW [port#]
X
X (default: 8195 = AMIGTERM (talk window))
X
X Connect to the remote port and place the TTY in RAW mode. The
X connection can only be terminated by the remote end, or by killing
X the process on the UNIX end.
X
X The default port brings up a 'talk' window on the Amiga. AMIGATERM
X will recognize a ^C sent from DRAW and close the connection.
X
SHAR_EOF
if `test ! -d lib`
then
mkdir lib
echo "mkdir lib"
fi
echo "extracting lib/dnetlib.h"
sed 's/^X//' << \SHAR_EOF > lib/dnetlib.h
X
X#define EFATAL 0
X#define EWARN 1
X#define EDEBUG 2
X
SHAR_EOF
echo "extracting lib/dnetlib.c"
sed 's/^X//' << \SHAR_EOF > lib/dnetlib.c
X
X/*
X * DNETLIB.C
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X *
X * Library Interface for DNET.
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <stdio.h>
X#include <errno.h>
X#ifdef O_CREAT
X#include <sys/file.h>
X#endif
X#include "../lib/dnetlib.h"
X
Xextern char *getenv();
X
Xtypedef unsigned short uword;
Xtypedef unsigned long ulong;
Xtypedef unsigned char ubyte;
Xtypedef struct sockaddr SOCKADDR;
X
Xtypedef struct {
X int s;
X uword port;
X} CHANN;
X
X#define NAMELEN sizeof(".PORT.XXXXX")
X#define NAMEPAT "%s.PORT.%ld"
X
Xchar *getdirpart();
X
XCHANN *
XDListen(port)
Xuword port;
X{
X CHANN *chan;
X int s;
X SOCKADDR *sa = (SOCKADDR *)malloc(sizeof(SOCKADDR)+256);
X char *dirstr = getenv("DNETDIR") ? getenv("DNETDIR") : "";
X
X sprintf(sa->sa_data, NAMEPAT, dirstr, port);
X sa->sa_family = AF_UNIX;
X unlink(sa->sa_data);
X
X s = socket(PF_UNIX, SOCK_STREAM, 0);
X fcntl(s, F_SETOWN, getpid());
X if (bind(s, sa, sizeof(*sa)-sizeof(sa->sa_data)+strlen(sa->sa_data)) < 0) {
X close(s);
X free(sa);
X return(NULL);
X }
X if (listen(s, 5) < 0) {
X close(s);
X unlink(sa->sa_data);
X free(sa);
X return(NULL);
X }
X chan = (CHANN *)malloc(sizeof(CHANN));
X chan->s = s;
X chan->port = port;
X free(sa);
X return(chan);
X}
X
X
XDUnListen(chan)
XCHANN *chan;
X{
X char *dirstr = getenv("DNETDIR") ? getenv("DNETDIR") : "";
X char buf[32];
X
X close(chan->s);
X sprintf(buf, NAMEPAT, dirstr, chan->port);
X unlink(buf);
X free(chan);
X}
X
XDAccept(chan)
XCHANN *chan;
X{
X SOCKADDR sa;
X int addrlen = sizeof(sa);
X int fd;
X
X fd = accept(chan->s, &sa, &addrlen);
X return(fd);
X}
X
XDOpen(host, port, txpri, rxpri)
Xchar *host;
Xuword port;
Xchar txpri, rxpri;
X{
X int s;
X char rc;
X short xb[3];
X SOCKADDR *sa = (SOCKADDR *)malloc(sizeof(SOCKADDR)+256);
X char *dirstr = getenv("DNETDIR") ? getenv("DNETDIR") : "";
X
X if (rxpri < -127)
X rxpri = -127;
X if (rxpri > 126)
X rxpri = 126;
X if (txpri < -127)
X txpri = -127;
X if (txpri > 126)
X txpri = 126;
X
X if (host == NULL)
X host = (getenv("DNETHOST")) ? getenv("DNETHOST"):"";
X
X sa->sa_family = AF_INET;
X sprintf(sa->sa_data, "%s%s%s", dirstr, "DNET.", host);
X
X s = socket(PF_UNIX, SOCK_STREAM, 0);
X fcntl(s, F_SETOWN, getpid());
X if (connect(s, sa, sizeof(*sa)-sizeof(sa->sa_data)+
X strlen(sa->sa_data))<0) {
X close(s);
X free(sa);
X return(-1);
X }
X free(sa);
X xb[0] = port;
X ((char *)&xb[1])[0] = txpri;
X ((char *)&xb[1])[1] = rxpri;
X write(s, xb, 4);
X if (read(s, &rc, 1) == 1 && rc == 0)
X return(s);
X close(s);
X return(-1);
X}
X
XDEof(fd)
X{
X char dummy;
X
X shutdown(fd, 1);
X write(fd, &dummy, 0);
X}
X
Xgwrite(fd, buf, bytes)
Xchar *buf;
X{
X int n;
X int orig = bytes;
X extern int errno;
X while (bytes) {
X n = write(fd, buf, bytes);
X if (n > 0) {
X bytes -= n;
X buf += n;
X continue;
X }
X if (n < 0) {
X if (errno == EINTR)
X continue;
X if (errno == EWOULDBLOCK) {
X int wm = 1 << fd;
X int em = 1 << fd;
X if (select(fd+1, NULL, &wm, &em, NULL) < 0)
X continue;
X if (wm)
X continue;
X }
X return(orig - bytes);
X }
X }
X return(orig);
X}
X
Xgread(fd, buf, bytes)
Xchar *buf;
X{
X int n;
X int orig = bytes;
X extern int errno;
X while (bytes) {
X n = read(fd, buf, bytes);
X if (n > 0) {
X bytes -= n;
X buf += n;
X break;
X }
X if (n < 0) {
X if (errno == EINTR)
X continue;
X if (errno == EWOULDBLOCK) {
X int rm = 1 << fd;
X int em = 1 << fd;
X if (select(fd+1, &rm, NULL, &em, NULL) < 0)
X continue;
X if (rm)
X continue;
X }
X return(orig - bytes);
X }
X if (n == 0)
X break;
X }
X return(orig - bytes);
X}
X
Xggread(fd, buf, bytes)
Xchar *buf;
X{
X int n;
X int ttl = 0;
X while (bytes) {
X n = gread(fd, buf, bytes);
X if (n > 0) {
X bytes -= n;
X buf += n;
X ttl += n;
X continue;
X }
X return(-1);
X }
X return(ttl);
X}
X
X/*
X * Convert to and from 68000 longword format. Of course, it really
X * doesn't matter what format you use, just as long as it is defined.
X */
X
Xntohl68(n)
Xulong n;
X{
X return(
X (((ubyte *)&n)[0] << 24)|
X (((ubyte *)&n)[1] << 16)|
X (((ubyte *)&n)[2] << 8)|
X (((ubyte *)&n)[3])
X );
X}
X
Xhtonl68(n)
Xulong n;
X{
X ulong v;
X ((ubyte *)&v)[0] = n >> 24;
X ((ubyte *)&v)[1] = n >> 16;
X ((ubyte *)&v)[2] = n >> 8;
X ((ubyte *)&v)[3] = n;
X return(v);
X}
X
X
XDoOption(ac, av, ops, args)
Xshort ac;
Xchar *av[];
Xchar *ops;
Xlong args;
X{
X register short i;
X short j;
X
X for (i = j = 1; i < ac; ++i) {
X register char *ptr = av[i];
X if (*ptr != '-') {
X av[j++] = av[i];
X continue;
X }
X while (*++ptr) {
X register char *op;
X long **ap = (long **)&args;
X short isshort;
X
X for (op = ops; *op && *op != *ptr;) {
X if (*op == *ptr)
X break;
X if (*++op == '%') {
X while (*op && *op != 's' && *op != 'd')
X ++op;
X if (*op)
X ++op;
X }
X if (*op == ',') /* optional , */
X ++op;
X ++ap;
X }
X if (*op == 0)
X return(-1);
X if (op[1] != '%') {
X *(short *)*ap = 1;
X ++ap;
X continue;
X }
X op += 2;
X isshort = 1;
X while (*op && *op != 's' && *op != 'd') {
X switch(*op) {
X case 'h':
X isshort = 1;
X break;
X case 'l':
X isshort = 0;
X break;
X default:
X return(-1);
X }
X ++op;
X }
X switch(*op) {
X case 's':
X if (ptr[1]) {
X *(char **)*ap = ptr + 1;
X ptr = "\0";
X } else {
X *(char **)*ap = av[++i];
X }
X break;
X case 'd':
X if (isshort)
X *(short *)*ap = atoi(++ptr);
X else
X *(long *)*ap = atoi(++ptr);
X while (*ptr >= '0' && *ptr <= '9')
X ++ptr;
X break;
X default:
X return(-1);
X }
X }
X }
X return(j);
X}
X
Xelog(how, ctl, arg)
Xchar *ctl;
Xlong arg;
X{
X char *dir = getenv("DNETDIR");
X FILE *fi;
X char buf[256];
X long dtime;
X
X time(&dtime);
X
X if (!dir)
X dir = "";
X sprintf(buf, "%s%s", dir, "DNET.LOG");
X if (fi = fopen(buf, "a")) {
X strcpy(buf, ctime(&dtime));
X buf[strlen(buf)-1] = 0;
X fprintf(fi, "%s ", buf);
X fprintf(fi, ctl, arg);
X putc('\n', fi);
X fclose(fi);
X }
X if (how == EFATAL)
X exit(1);
X}
X
SHAR_EOF
echo "extracting lib/Makefile"
sed 's/^X//' << \SHAR_EOF > lib/Makefile
X
X
Xdnetlib.o : dnetlib.c
X cc -c dnetlib.c
X
SHAR_EOF
if `test ! -d server`
then
mkdir server
echo "mkdir server"
fi
echo "extracting server/sgcopy.c"
sed 's/^X//' << \SHAR_EOF > server/sgcopy.c
X
X/*
X * SGCOPY.C V1.1
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
X *
X * GET-COPY SERVER (NEW COPY SERVER)
X *
X * The current version only accepts one connection at a time. This server
X * will send requested files to the remote machine.
X *
X * length in 68000 longword format.
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <sys/time.h>
X#include <sys/dir.h>
X#include <sys/file.h>
X#include <sys/resource.h>
X#include <stdio.h>
X#include <errno.h>
X#include <signal.h>
X
X#include "servers.h"
X
Xtypedef struct {
X char Cmd;
X char Str[64];
X long Val;
X} HDR;
X
Xtypedef unsigned char ubyte;
Xchar *getnamepart();
Xchar *getdirpart();
X
Xchar Buf[4096];
Xint Chan;
X
Xchandler()
X{
X union wait stat;
X struct rusage rus;
X while (wait3(&stat, WNOHANG, &rus) > 0);
X}
X
Xmain(ac,av)
Xchar *av[];
X{
X long chann = DListen(PORT_GFILECOPY);
X int fd;
X int n;
X char buf[256];
X extern int errno;
X
X if (av[1])
X chdir(av[1]);
X signal(SIGCHLD, chandler);
X signal(SIGPIPE, SIG_IGN);
X for (;;) {
X fd = DAccept(chann);
X if (fd < 0) {
X if (errno == EINTR)
X continue;
X break;
X }
X if (fork() == NULL) {
X SGCopy(fd);
X _exit(1);
X }
X close(fd);
X }
X perror("SCOPY");
X}
X
XSGCopy(fd)
Xint fd;
X{
X short error = 0;
X static HDR Hdr;
X
X Chan = fd;
X error = WriteHeader('H', "Hello, GCopy server V1.30", 0);
X if (error)
X return(error);
X switch(ReadHeader(&Hdr)) {
X default:
X case -1:
X error = 1;
X return(error);
X case 'H':
X break;
X }
X while (!error) {
X switch(ReadHeader(&Hdr)) {
X case 'G':
X {
X char svdir[1024];
X getwd(svdir);
X if (chdir(getdirpart(Hdr.Str)) < 0) {
X error = WriteHeader('N', "Unable to cd to dir", 0);
X } else {
X error = PutObject(getnamepart(Hdr.Str));
X }
X chdir(svdir);
X }
X break;
X case 'E':
X goto done;
X case 'P': /* put-files, not implemented */
X default:
X error = 1;
X break;
X }
X }
Xdone:
X ;
X}
X
XPutObject(str)
Xchar *str;
X{
X struct stat stat;
X short error = 0;
X
X if (lstat(str, &stat) < 0) {
X error = WriteHeader('N', "Unable to find object", 0);
X return(0);
X }
X if (stat.st_mode & S_IFDIR) {
X error = PutDir(str);
X } else {
X error = PutFile(str);
X }
X return(0);
X}
X
XPutDir(name)
Xchar *name;
X{
X struct stat stat;
X char svdir[1024];
X static HDR Hdr;
X short error = 0;
X char *fn = getnamepart(name);
X DIR *dir;
X struct direct *de;
X
X if (lstat(name, &stat) < 0 || !(dir = opendir(name))) {
X WriteHeader('N', "Possible Disk Error", 0);
X error = 1;
X goto done;
X }
X if (error = WriteHeader('D', fn, 0))
X goto done;
X switch(ReadHeader(&Hdr)) {
X case 'Y':
X break;
X case 'S':
X goto done;
X case 'N':
X error = 1;
X break;
X default:
X error = 1;
X break;
X }
X if (error)
X goto done;
X
X getwd(svdir);
X if (chdir(name) < 0) {
X error = 1;
X WriteHeader('N', "unable to chdir", 0);
X }
X if (error)
X goto done;
X
X while (de = readdir(dir)) {
X if (strcmp(de->d_name, ".") == 0)
X continue;
X if (strcmp(de->d_name, "..") == 0)
X continue;
X if (lstat(de->d_name, &stat) < 0) {
X continue;
X }
X if (stat.st_mode & S_IFDIR) {
X error = PutDir(de->d_name);
X } else {
X error = PutFile(de->d_name);
X }
X if (error)
X break;
X }
X WriteHeader('E', NULL, 0);
X chdir(svdir);
Xdone:
X return(error);
X}
X
XPutFile(name)
Xchar *name;
X{
X int fd = -1;
X static HDR Hdr;
X long len;
X short error = 0;
X char *fn = getnamepart(name);
X
X fd = open(fn, O_RDONLY, 0);
X if (fd < 0) { /* don't do anything if unable to open it */
X WriteHeader('N', "file not readable", 0);
X goto done;
X }
X len = lseek(fd, 0L, 2);
X if (error = WriteHeader('F', fn, len))
X goto done;
X switch(ReadHeader(&Hdr)) {
X case 'Y':
X lseek(fd, Hdr.Val, 0); /* start pos. */
X len -= Hdr.Val;
X if (len < 0)
X len = 0;
X break;
X case 'S':
X goto done;
X case 'N':
X error = 1;
X break;
X default:
X error = 1;
X break;
X }
X if (error)
X goto done;
X while (len) {
X register long n = (len > sizeof(Buf)) ? sizeof(Buf) : len;
X
X if (read(fd, Buf, n) != n) { /* read failed! */
X error = 10;
X goto done;
X }
X if (gwrite(Chan, Buf, n) != n) {
X error = 10;
X goto done;
X }
X len -= n;
X }
Xdone:
X if (fd >= 0)
X close(fd);
X return(error);
X}
X
X
XWriteHeader(c, str, len)
Xchar c;
Xchar *str;
Xlong len;
X{
X ubyte sl;
X
X if (str == NULL)
X str = "";
X sl = strlen(str);
X
X if (gwrite(Chan, &c, 1) < 0)
X return(1);
X if (gwrite(Chan, &sl,1) < 0)
X return(1);
X if (gwrite(Chan, str, sl) != sl)
X return(1);
X len = htonl68(len);
X if (gwrite(Chan, &len, 4) != 4)
X return(1);
X return(0);
X}
X
XReadHeader(hdr)
XHDR *hdr;
X{
X ubyte sl;
X ubyte cmd;
X
X hdr->Cmd = -1;
X if (ggread(Chan, &cmd, 1) != 1)
X return(-1);
X if (ggread(Chan, &sl, 1) != 1)
X return(-1);
X if (sl >= sizeof(hdr->Str)) {
X return(-1);
X }
X if (ggread(Chan, hdr->Str, sl) != sl)
X return(-1);
X hdr->Str[sl] = 0;
X if (ggread(Chan, &hdr->Val, 4) != 4)
X return(-1);
X hdr->Val = ntohl68(hdr->Val);
X hdr->Cmd = cmd;
X return(hdr->Cmd);
X}
X
Xchar *
Xgetnamepart(str)
Xchar *str;
X{
X register char *ptr = str + strlen(str);
X
X while (ptr >= str) {
X if (*ptr == '/')
X break;
X --ptr;
X }
X return(ptr+1);
X}
X
Xchar *
Xgetdirpart(str)
Xchar *str;
X{
X static char buf[1024];
X
X strcpy(buf, str);
X getnamepart(buf)[0] = 0;
X if (buf[0] == 0)
X return(".");
X return(buf);
X}
SHAR_EOF
echo "extracting server/sshell.c"
sed 's/^X//' << \SHAR_EOF > server/sshell.c
X
X/*
X * S_SHELL.C OBSOLETE OBSOLETE OBSOLETE
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X *
X * Connect a csh to a pseudo terminal pair... PORT_ALPHATERM
X * NOTE!! PORT_IALPHATERM (a pseudo-terminal csh) is also available
X * through the FTERM client program on the Amiga side, and much faster
X * since the server for PORT_IALPHATERM is DNET itself (one less process
X * to go through).
X *
X * -doesn't handle SIGWINCH
X * -doesn't handle flow control ... don't cat any long files!
X */
X
X#include <stdio.h>
X#include <sys/wait.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <errno.h>
X#include <signal.h>
X
X#include "servers.h"
X
Xchandler()
X{
X union wait stat;
X struct rusage rus;
X while (wait3(&stat, WNOHANG, &rus) > 0);
X}
X
Xmain(ac,av)
Xchar *av[];
X{
X long chann = DListen(PORT_ALPHATERM);
X int fd;
X int n;
X char buf[256];
X extern int errno;
X
X if (av[1])
X chdir(av[1]);
X signal(SIGCHLD, chandler);
X signal(SIGPIPE, SIG_IGN);
X for (;;) {
X fd = DAccept(chann);
X if (fd < 0) {
X if (errno == EINTR)
X continue;
X break;
X }
X if (fork() == NULL) {
X dup2(fd, 0);
X dup2(fd, 1);
X dup2(fd, 2);
X close(fd);
X execl("/usr/ucb/rlogin", "rlogin", "localhost", NULL);
X exit(1);
X }
X close(fd);
X }
X perror("SSHELL");
X}
X
SHAR_EOF
echo "extracting server/sloadav.c"
sed 's/^X//' << \SHAR_EOF > server/sloadav.c
X
X/*
X * SLOADAV.C
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X *
X * Reports the load average every 5 minutes or until the connection
X * is closed.
X */
X
X#include <stdio.h>
X#include <sys/wait.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <errno.h>
X#include <signal.h>
X
X#include "servers.h"
X
Xchandler()
X{
X union wait stat;
X struct rusage rus;
X while (wait3(&stat, WNOHANG, &rus) > 0);
X}
X
Xmain(ac,av)
Xchar *av[];
X{
X long chann = DListen(PORT_LOADAV);
X int fd;
X int n;
X char buf[256];
X extern int errno;
X
X if (av[1])
X chdir(av[1]);
X signal(SIGCHLD, chandler);
X signal(SIGPIPE, SIG_IGN);
X for (;;) {
X fd = DAccept(chann);
X if (fd < 0) {
X if (errno == EINTR)
X continue;
X break;
X }
X if (fork() == NULL) {
X do_loadav(fd);
X close(fd);
X _exit(1);
X }
X close(fd);
X }
X perror("SLOADAV");
X}
X
Xdo_loadav(fd)
X{
X char dummy;
X char buf[256];
X FILE *fi;
X
X while (ggread(fd, &dummy, 1) == 1) {
X fi = popen("uptime", "r");
X if (fi == NULL)
X break;
X if (fgets(buf, 256, fi)) {
X dummy = strlen(buf);
X buf[dummy-1] = 0;
X gwrite(fd, &dummy, 1);
X gwrite(fd, buf, dummy);
X }
X if (ferror(fi))
X break;
X pclose(fi);
X }
X}
X
SHAR_EOF
echo "extracting server/scopy.c"
sed 's/^X//' << \SHAR_EOF > server/scopy.c
X
X/*
X * SCOPY.C
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X *
X * Remote file copy server (putfiles is the client program)
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/wait.h>
X#include <sys/time.h>
X#include <sys/file.h>
X#include <sys/resource.h>
X#include <stdio.h>
X#include <errno.h>
X#include <signal.h>
X
X#include "servers.h"
X#include "../lib/dnetlib.h"
X
Xchar Buf[4096];
X
Xchandler()
X{
X union wait stat;
X struct rusage rus;
X while (wait3(&stat, WNOHANG, &rus) > 0);
X}
X
Xmain(ac,av)
Xchar *av[];
X{
X long chann = DListen(PORT_FILECOPY);
X int fd;
X int n;
X char buf[256];
X extern int errno;
X
X elog(EDEBUG, "SCOPY START", 0);
X if (av[1])
X chdir(av[1]);
X signal(SIGCHLD, chandler);
X signal(SIGPIPE, SIG_IGN);
X for (;;) {
X fd = DAccept(chann);
X if (fd < 0) {
X if (errno == EINTR)
X continue;
X break;
X }
X elog(EDEBUG, "SCOPY CONNECT", 0);
X if (fork() == NULL) {
X putdir(fd, ".");
X _exit(1);
X }
X close(fd);
X }
X perror("SCOPY");
X}
X
Xputdir(chan, dirname)
Xchar *dirname;
X{
X struct stat stat;
X char olddir[256];
X char co, nl, name[128];
X long len;
X int ret = -1;
X
X getwd(olddir);
X if (lstat(dirname, &stat) >= 0 && !(stat.st_mode & S_IFDIR)) {
X char rc = 'N';
X gwrite(chan, &rc, 1);
X elog(EWARN, "SCOPY: Unable to cd to dir '%s'", dirname);
X return(1);
X }
X if (chdir(dirname) < 0) {
X if (mkdir(dirname, 0777) < 0 || chdir(dirname) < 0) {
X char rc = 'N';
X elog(EWARN, "SCOPY: Unable to create directory '%s'", dirname);
X gwrite(chan, &rc, 1);
X return(1);
X }
X }
X co = 'Y';
X gwrite(chan, &co, 1);
X while (ggread(chan, &co, 1) == 1) {
X if (ggread(chan, &nl, 1) != 1 || ggread(chan, name, nl) != nl)
X break;
X if (ggread(chan, &len, 4) != 4)
X break;
X len = ntohl68(len);
X switch(co) {
X case 'C':
X co = 'Y';
X if (chdir(name) < 0) {
X if (mkdir(name, 0777) < 0 || chdir(name) < 0) {
X co = 'N';
X elog(EWARN, "SCOPY: Unable to create directory '%s'",
X dirname);
X }
X }
X gwrite(chan, &co, 1);
X break;
X case 'W':
X if (putfile(chan, name, len) < 0) {
X ret = -1;
X elog(EWARN, "SCOPY: Failure on file %.*s", len, name);
X goto fail;
X }
X break;
X case 'X':
X if (putdir(chan, name) < 0) {
X ret = -1;
X goto fail;
X }
X break;
X case 'Y':
X ret = 1;
X co = 'Y';
X gwrite(chan, &co, 1);
X goto fail;
X default:
X co = 'N';
X gwrite(chan, &co, 1);
X break;
X }
X }
Xfail:
X chdir(olddir);
X return(ret);
X}
X
Xputfile(chan, name, len)
Xchar *name;
X{
X long fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
X long n, r;
X char rc;
X
X if (fd < 0) {
X rc = 'N';
X gwrite(chan, &rc, 1);
X return(0);
X }
X rc = 'Y';
X gwrite(chan, &rc, 1);
X while (len) {
X r = (len > sizeof(Buf)) ? sizeof(Buf) : len;
X n = ggread(chan, Buf, r);
X if (n != r)
X break;
X if (write(fd, Buf, n) != n)
X break;
X len -= n;
X }
X close(fd);
X if (len) {
X unlink(name);
X return(-1);
X }
X rc = 'Y';
X gwrite(chan, &rc, 1);
X return(0);
X}
X
SHAR_EOF
echo "extracting server/Makefile"
sed 's/^X//' << \SHAR_EOF > server/Makefile
X
X# DNET SERVERS
X#
X#
X# DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X
XNETLIB = ../lib/dnetlib.o
XBIN = ../bin
X
X
Xall: $(NETLIB) $(BIN)/scopy $(BIN)/sshell \
X $(BIN)/sloadav $(BIN)/sgcopy
X
X$(BIN)/scopy: scopy.o
X cc scopy.o $(NETLIB) -o $(BIN)/scopy
X
X$(BIN)/sgcopy: sgcopy.o
X cc sgcopy.o $(NETLIB) -o $(BIN)/sgcopy
X
X$(BIN)/sshell: sshell.o
X cc sshell.o $(NETLIB) -o $(BIN)/sshell
X
X$(BIN)/sloadav: sloadav.o
X cc sloadav.o $(NETLIB) -o $(BIN)/sloadav
X
Xclean:
X rm -f *.o make.out
X
SHAR_EOF
echo "extracting server/servers.h"
sed 's/^X//' << \SHAR_EOF > server/servers.h
X
X/*
X * SERVERS.H
X *
X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
X */
X
X#define PORT_FILECOPY 8192
X#define PORT_ALPHATERM 8193
X#define PORT_ECHO 8194
X#define PORT_IALPHATERM 8195
X#define PORT_AMIGATERM 8195
X#define PORT_AMIGASHELL 8196
X#define PORT_LOADAV 8197
X#define PORT_PRINTER 8198
X#define PORT_PASSWD 8199
X#define PORT_BBS 8200
X#define PORT_GFILECOPY 8201
X
X
SHAR_EOF
echo "End of archive 2 (of 2)"
# if you want to concatenate archives, remove anything after this line
exit